package com.capgemini.cn.authority.rest.service.impl;

import com.capgemini.cn.authority.data.entity.Groups;
import com.capgemini.cn.authority.data.entity.Roles;
import com.capgemini.cn.authority.data.repository.GroupsRepository;
import com.capgemini.cn.authority.data.repository.RolesRepository;
import com.capgemini.cn.authority.rest.exception.AuthRestBusinessException;
import com.capgemini.cn.authority.rest.service.AbstractBaseService;
import com.capgemini.cn.authority.rest.service.GroupService;
import com.capgemini.cn.authority.rest.valueobject.DataPage;
import com.capgemini.cn.authority.rest.valueobject.DataResponse;
import com.capgemini.cn.authority.rest.valueobject.data.GroupListVO;
import com.capgemini.cn.authority.rest.valueobject.data.GroupVO;
import lombok.Getter;
import lombok.Setter;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;

import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * Created at 2017/9/18
 *
 * @author Andriy
 */
@Service(value = GroupServiceImpl.COMPONENT_NAME)
public class GroupServiceImpl extends AbstractBaseService<GroupVO, Groups> implements GroupService {

    public static final String COMPONENT_NAME = "groupService";

    private final String[] IGNORE_PROPERTIES = {
            "groupMembers",
            "roles",
            "childrenGroups"
    };

    @Autowired
    @Getter
    @Setter
    private GroupsRepository groupsRepository;

    @Autowired
    @Getter
    @Setter
    private RolesRepository rolesRepository;

    @Transactional(readOnly = true)
    @Override
    public DataResponse<GroupVO> findById(long id) {
        return super.findById(GroupVO.class, id, this.IGNORE_PROPERTIES);
    }

    @Transactional(readOnly = true)
    @Override
    public DataResponse<List<GroupVO>> findAll(int page, int size, String orderProp, Sort.Direction direction) {
        return super.findAll(GroupVO.class, page, size, orderProp, direction, this.IGNORE_PROPERTIES);
    }

    @Transactional
    @Override
    public DataResponse<GroupVO> add(GroupVO source) {
        Groups entity = new Groups(source.getGroupName());
        // 校验判断设置父级和根级用户组的方式
        // 如果有父用户组ID值则进行对应的查询和关联操作
        // 没有设置父用户组ID值则认为是创建根用户组，此时父级和根级用户组的属性值均为空
        if (!ObjectUtils.isEmpty(source.getTmpParentId())) {
            Groups parentGroup = super.getRepository().findOne(source.getTmpParentId());
            if (ObjectUtils.isEmpty(parentGroup)) {
                throw new AuthRestBusinessException("父用户组不存在，请重新选择！");
            }
            entity.setParentGroup(parentGroup);
            entity.setRootGroupId(parentGroup.getRootGroupId());
        } else {
            Groups savedEntity = super.getRepository().save(entity);
            // 对于根用户组则需要把自己设置到对应的属性中去
            savedEntity.setRootGroupId(savedEntity.getId());
            entity = savedEntity;
        }
        return new DataResponse<GroupVO>().setResponse(super.conversionToValueObject(super.getRepository().saveAndFlush(entity), GroupVO.class, this.IGNORE_PROPERTIES));
    }

    @Transactional
    @Override
    public boolean add(List<GroupVO> sourceList) {
        return false;
    }

    @Transactional
    @Override
    public DataResponse<GroupVO> update(long id, Map<String, Object> properties) throws AuthRestBusinessException {
        return super.update(GroupVO.class, id, properties, this.IGNORE_PROPERTIES);
    }

    @Transactional
    @Override
    public boolean update(Map<String, Object> properties, List<GroupVO> sourceList) {
        return false;
    }

    @Transactional
    @Override
    public DataResponse<GroupListVO> findDetail(long id) {
        Groups entity = this.groupsRepository.findOne(id);
        if (ObjectUtils.isEmpty(entity)) {
            throw new AuthRestBusinessException("无法根据主键ID（" + id + "）查询到对应的用户组信息！");
        }
        GroupListVO groupListVO = new GroupListVO();
        BeanUtils.copyProperties(entity, groupListVO, this.IGNORE_PROPERTIES);
        for (Groups childEntity : entity.getChildrenGroups()) {
            GroupVO groupVO = super.conversionToValueObject(childEntity, GroupVO.class, this.IGNORE_PROPERTIES);
            groupListVO.getChildGroups().add(groupVO);
        }
        return new DataResponse<GroupListVO>().setResponse(groupListVO);
    }

    @Transactional
    @Override
    public DataResponse<List<GroupVO>> findAll(boolean isSearchRoot, int page, int size, String orderProp, Sort.Direction direction) {
        DataResponse<List<GroupVO>> result = new DataResponse<>();

        Page<Groups> pageEntities;
        List<Groups> entities;
        // 只有size参数有效时才会进行分页查询
        if (size > 0) {
            if (isSearchRoot) {
                pageEntities = this.groupsRepository.findAllByParentGroupIsNull(new PageRequest(page, size, direction, orderProp));
            } else {
                pageEntities = super.getRepository().findAll(new PageRequest(page, size, direction, orderProp));
            }
            entities = pageEntities.getContent();
            result.setPages(new DataPage(pageEntities.getTotalPages(), pageEntities.getTotalElements(), pageEntities.getNumber(), pageEntities.getSize(), pageEntities.isFirst(), pageEntities.isLast()));
        } else {
            if (isSearchRoot) {
                entities = this.groupsRepository.findAllByParentGroupIsNull(new Sort(direction, orderProp));
            } else {
                entities = super.getRepository().findAll(new Sort(direction, orderProp));
            }
        }
        List<GroupVO> resultList = new ArrayList<>();
        for (Groups entity : entities)
            resultList.add(this.conversionToValueObject(entity, GroupVO.class, this.IGNORE_PROPERTIES));
        result.setResponse(resultList);
        return result;
    }

    @Transactional(readOnly = true)
    @Override
    public DataResponse<List<GroupVO>> findGroupByRole(Long roleId) throws AuthRestBusinessException {
        Roles roleEntity = this.rolesRepository.findOne(roleId);
        if (ObjectUtils.isEmpty(roleEntity))
            throw new AuthRestBusinessException("无法根据主键ID（" + roleId + "）查询到对应的角色实体对象信息！");
        List<Groups> groupList = roleEntity.getGroupsList();
        List<GroupVO> resultList = new ArrayList<>();
        for (Groups entity : groupList)
            resultList.add(this.conversionToValueObject(entity, GroupVO.class));
        return new DataResponse<List<GroupVO>>().setResponse(resultList);
    }

    @Transactional
    @Override
    public DataResponse<GroupVO> update(Long id, Long parentId, Map<String, Object> properties) throws AuthRestBusinessException {
        DataResponse<GroupVO> result;
        if (ObjectUtils.isEmpty(parentId)) {
            result = super.update(GroupVO.class, id, properties, this.IGNORE_PROPERTIES);
        } else {
            Groups parentGroup = super.getRepository().findOne(parentId);
            if (ObjectUtils.isEmpty(parentGroup)) {
                throw new AuthRestBusinessException("父用户组不存在，请重新选择！");
            }
            Groups sourceGroup = super.getRepository().findOne(id);
            if (ObjectUtils.isEmpty(sourceGroup)) {
                throw new AuthRestBusinessException("无法根据主键ID（" + id + "）查询到对应的实体对象信息！");
            }
            // 将需要更新的属性设置到实体对象中
            super.copyProperties(sourceGroup, GroupVO.class, properties);
            // 设置更新时间
            sourceGroup.setUpdateTime(new Timestamp(System.currentTimeMillis()));
            // 更新父级用户组
            sourceGroup.setParentGroup(parentGroup);
            // 更新根用户组主键ID值
            sourceGroup.setRootGroupId(parentGroup.getRootGroupId());
            // 执行更新操作
            Groups updatedEntity = this.getRepository().saveAndFlush(sourceGroup);
            // 将实体对象转换成值对象并返回
            result = new DataResponse<GroupVO>().setResponse(super.conversionToValueObject(updatedEntity, GroupVO.class, this.IGNORE_PROPERTIES));
        }
        return result;
    }

    @Transactional
    @Override
    public boolean delete(long id) throws AuthRestBusinessException {
        Groups group = super.getRepository().findOne(id);
        if (ObjectUtils.isEmpty(group)) {
            throw new AuthRestBusinessException("无法根据主键ID（" + id + "）查询到对应的实体对象信息！");
        }
        if (!CollectionUtils.isEmpty(group.getChildrenGroups())) {
            throw new AuthRestBusinessException("当前分组下有" + group.getChildrenGroups().size() + "个子分组，请先解除关系再删除！");
        }
        return super.delete(id);
    }
}
